package com.ngis.model.mdl;

import java.util.ArrayList;

import org.dom4j.Element;

public class ModelAttribute {
	public ModelAttribute()
	{
		mLocalAttributeList = new ArrayList<LocalAttribute>();
		mModelCategoryList = new ArrayList<ModelCategory>();
		this.mAuthors = new ArrayList<ModelUser>();
		this.mBuilders = new ArrayList<ModelUser>();
		this.mWrappers = new ArrayList<ModelUser>();
	}
	
	public boolean loadFromXml(Element pModelClassElement) {
		Element attributeEle = pModelClassElement.element("AttributeSet");

		Element categoriesEle = attributeEle.element("Categories");

        int count = categoriesEle.elements().size();
		for (int iCate = 0; iCate < count; iCate++) {
			Element childEle = (Element) categoriesEle.elements().get(iCate);
			ModelCategory modelCategory = new ModelCategory();
			modelCategory.principle = childEle.attributeValue("principle");
			modelCategory.path = childEle.attributeValue("path");
			mModelCategoryList.add(modelCategory);
		}

		Element localAttributesEle = attributeEle.element("LocalAttributes");
		count = localAttributesEle.elements().size();
		for (int iLocal = 0; iLocal < count; iLocal++) {
			Element childEle = (Element) localAttributesEle.elements().get(iLocal);

			LocalAttribute localAttribute = new LocalAttribute();
			localAttribute.localName = childEle.attributeValue("localName");
			localAttribute.wikiUrl = childEle.attributeValue("wiki");
			String localTypeStr = childEle.attributeValue("local");
			ELocalizationType localType = LocalizationHelper
					.String2LocalizationType(localTypeStr);

			localAttribute.localType = localType;
			Element keywords_ele = childEle.element("Keywords");
			Element abstract_ele = childEle.element("Abstract");
			String keywords_str = keywords_ele.getText();
			localAttribute.abstractInfo = abstract_ele.getText();

			String[] ret = keywords_str.split(";");
			for (int iKey = 0; iKey < ret.length; iKey++) {
				localAttribute.keywords.add(ret[iKey]);
			}
			
			Element mechanismsEle = childEle.element("LocalAttributes");
			if(mechanismsEle != null) {
				for (int indexM = 0; indexM < mechanismsEle.elements().size(); indexM++) {
					Element mChildEle = (Element) mechanismsEle.elements().get(indexM);
					EMechanismItemType type = LocalizationHelper.String2MechanismItemType(mChildEle.attributeValue("type"));
					String name = mChildEle.attributeValue("name");
					String value;
					if (type == EMechanismItemType.EMIT_Text) {
						value = mChildEle.getText();
					}
					else {
						value = mChildEle.attributeValue("value");
					}
					ModelMechanismItem mItem = new ModelMechanismItem(name, type, value);
					localAttribute.mechanismItems.add(mItem);
				}
			}

			Element applicationEle = childEle.element("Application");
			if (applicationEle != null) {
				Element spatiotemporalScaleEle = applicationEle.element("SpatiotemporalScale");
				if (spatiotemporalScaleEle != null) {
					localAttribute.sptimeScaleType = LocalizationHelper.String2ESpatiotemporalScaleType(spatiotemporalScaleEle.attributeValue("type"), spatiotemporalScaleEle.attributeValue("scale"));
				}
				
				Element spatiotemporalStepLengthEle = applicationEle.element("SpatiotemporalStepLength");
				if (spatiotemporalStepLengthEle != null) {
					Element spatiotemporalStepLengthXEle = spatiotemporalStepLengthEle.element("X");
					String ssstep = spatiotemporalStepLengthXEle.attributeValue("step");
					localAttribute.sslX = new SpatiotemporalStepLength(spatiotemporalStepLengthXEle.attributeValue("step"), spatiotemporalStepLengthXEle.attributeValue("unit"));
					Element spatiotemporalStepLengthYEle = spatiotemporalStepLengthEle.element("T");
					localAttribute.sslY = new SpatiotemporalStepLength(spatiotemporalStepLengthYEle.attributeValue("step"), spatiotemporalStepLengthYEle.attributeValue("unit"));
					Element spatiotemporalStepLengthZEle = spatiotemporalStepLengthEle.element("Z");
					localAttribute.sslZ = new SpatiotemporalStepLength(spatiotemporalStepLengthZEle.attributeValue("step"), spatiotemporalStepLengthZEle.attributeValue("unit"));
					Element spatiotemporalStepLengthTEle = spatiotemporalStepLengthEle.element("T");
					localAttribute.sslT = new SpatiotemporalStepLength(spatiotemporalStepLengthTEle.attributeValue("step"), spatiotemporalStepLengthTEle.attributeValue("unit"));
				}
				
				Element scopeEle = applicationEle.element("Scope");
				if (scopeEle != null) {
					Element extentGroupEle = scopeEle.element("ExtentGroup");
					if (extentGroupEle != null) {
						for (int eIndex = 0; eIndex < extentGroupEle.elements().size(); eIndex++) {
							Element extentEle = extentGroupEle.elements().get(eIndex);
							double xmin = Double.parseDouble(extentEle.attributeValue("xMin"));
							double xmax = Double.parseDouble(extentEle.attributeValue("xMax"));
							double ymin = Double.parseDouble(extentEle.attributeValue("yMin"));
							double ymax = Double.parseDouble(extentEle.attributeValue("yMax"));
							String reference = extentEle.attributeValue("spatialReference");
							SpatialExtent se = new SpatialExtent(xmin, xmax, ymin, ymax, reference);
							localAttribute.spatialScope.Extents.add(se);
						}
					}
					Element areaGroupEle = scopeEle.element("AreaGroup");
					if (areaGroupEle != null) {
						for (int aIndex = 0; aIndex < areaGroupEle.elements().size(); aIndex++) {
							Element areaEle = areaGroupEle.elements().get(aIndex);
							String name = areaEle.elements().get(aIndex).attributeValue("name");
							localAttribute.spatialScope.AreaNames.add(name);
						}
					}
				}
			}
			
			mLocalAttributeList.add(localAttribute);
		}

		Element authorsEle = attributeEle.element("Authors");
		this.mAuthors = LocalizationHelper.Xml2ModelUser(authorsEle);
		
		Element buildersEle = attributeEle.element("Builders");
		this.mBuilders = LocalizationHelper.Xml2ModelUser(buildersEle);
		
		Element wrappersEle = attributeEle.element("Wrappers");
		this.mWrappers = LocalizationHelper.Xml2ModelUser(wrappersEle);

		return true;
	}

	boolean formatToXml(Element pModelClassElement) {
		Element attributeEle = pModelClassElement.addElement("AttributeSet");

		Element categoriesEle = attributeEle.addElement("Categories");
		Element localAttributesEle = attributeEle.addElement("LocalAttributes");
		Element authorsEle = attributeEle.addElement("Authors");
		Element buildersEle = attributeEle.addElement("Builders");
		Element wrappersEle = attributeEle.addElement("Wrappers");

		for (int i = 0; i < mModelCategoryList.size(); i++) {
			ModelCategory temp_cate = mModelCategoryList.get(i);
			Element temp_ele = categoriesEle.addElement("Category");
			temp_ele.addAttribute("principle", temp_cate.principle);
			temp_ele.addAttribute("path", temp_cate.path);

		}

		for (int i = 0; i < mLocalAttributeList.size(); i++) {
			LocalAttribute temp_local = mLocalAttributeList.get(i);
			Element temp_ele = localAttributesEle.addElement("LocalAttribute");
			temp_ele.addAttribute("local", LocalizationHelper
					.LocalizationType2String(temp_local.localType));
			temp_ele.addAttribute("localName", temp_local.localName);
			temp_ele.addAttribute("wiki", temp_local.wikiUrl);

			Element keywordsEle = temp_ele.addElement("Keywords");
			Element abstractEle = temp_ele.addElement("Abstract");
			Element mechanismEle = temp_ele.addElement("Mechanism");
			Element applicationEle = temp_ele.addElement("Application");

			String keywords_str = "";
			for (int iKey = 0; iKey < temp_local.keywords.size(); iKey++) {
				String temp_str = temp_local.keywords.get(iKey);
				keywords_str += temp_str;
				if (iKey != temp_local.keywords.size() - 1)
					keywords_str += "; ";
			}
			keywordsEle.setText(keywords_str);

			abstractEle.setText(temp_local.abstractInfo);
			
			for(int mIndex = 0; mIndex < temp_local.mechanismItems.size(); mIndex++) {
				Element mEle = mechanismEle.addElement("Add");
				mEle.addAttribute("name", temp_local.mechanismItems.get(mIndex).Name);
				mEle.addAttribute("type", LocalizationHelper.MechanismItemType2String(temp_local.mechanismItems.get(mIndex).Type));
				if (temp_local.mechanismItems.get(mIndex).Type == EMechanismItemType.EMIT_Text) {
					mEle.setText(temp_local.mechanismItems.get(mIndex).Value);
				}
				else {
					mEle.addAttribute("value", temp_local.mechanismItems.get(mIndex).Value);
				}
			}
			
			//! Application
			Element spatiotemporalScaleEle = applicationEle.addElement("SpatiotemporalScale");
			spatiotemporalScaleEle.addAttribute("type", LocalizationHelper.ESpatiotemporalScaleType2String(mLocalAttributeList.get(i).sptimeScaleType));
			spatiotemporalScaleEle.addAttribute("scale", LocalizationHelper.ESpatiotemporalScale2String(mLocalAttributeList.get(i).sptimeScaleType));
			
			Element spatiotemporalStepLengthEle = applicationEle.addElement("SpatiotemporalStepLength");
			Element spatiotemporalStepLengthXEle = spatiotemporalStepLengthEle.addElement("X");
			spatiotemporalStepLengthXEle.addAttribute("step", "[" + String.valueOf(temp_local.sslX.Min) + "," + String.valueOf(temp_local.sslX.Max) + "]");
			spatiotemporalStepLengthXEle.addAttribute("unit", temp_local.sslX.Unit);
			Element spatiotemporalStepLengthYEle = spatiotemporalStepLengthEle.addElement("Y");
			spatiotemporalStepLengthYEle.addAttribute("step", "[" + String.valueOf(temp_local.sslY.Min) + "," + String.valueOf(temp_local.sslY.Max) + "]");
			spatiotemporalStepLengthYEle.addAttribute("unit", temp_local.sslY.Unit);
			Element spatiotemporalStepLengthZEle = spatiotemporalStepLengthEle.addElement("Z");
			spatiotemporalStepLengthZEle.addAttribute("step", "[" + String.valueOf(temp_local.sslZ.Min) + "," + String.valueOf(temp_local.sslZ.Max) + "]");
			spatiotemporalStepLengthZEle.addAttribute("unit", temp_local.sslZ.Unit);
			Element spatiotemporalStepLengthTEle = spatiotemporalStepLengthEle.addElement("T");
			spatiotemporalStepLengthTEle.addAttribute("step", "[" + String.valueOf(temp_local.sslT.Min) + "," + String.valueOf(temp_local.sslT.Max) + "]");
			spatiotemporalStepLengthTEle.addAttribute("unit", temp_local.sslT.Unit);
			
			Element scopeEle = applicationEle.addElement("Scope");
			for (int iExtent = 0; iExtent < temp_local.spatialScope.Extents.size(); iExtent ++) {
				Element temp_extent = scopeEle.addElement("Extent");
				temp_extent.addAttribute("xMin", String.valueOf(temp_local.spatialScope.Extents.get(iExtent).XMin));
				temp_extent.addAttribute("xMax", String.valueOf(temp_local.spatialScope.Extents.get(iExtent).XMax));
				temp_extent.addAttribute("yMin", String.valueOf(temp_local.spatialScope.Extents.get(iExtent).YMin));
				temp_extent.addAttribute("yMax", String.valueOf(temp_local.spatialScope.Extents.get(iExtent).YMax));
				temp_extent.addAttribute("spatialReference", temp_local.spatialScope.Extents.get(iExtent).SpatialReference);
			}
			
			for (int iArea = 0; iArea < temp_local.spatialScope.AreaNames.size(); iArea ++) {
				Element temp_area = scopeEle.addElement("Area");
				temp_area.addAttribute("name", temp_local.spatialScope.AreaNames.get(iArea));
			}
		}
		
		for (int index = 0; index < this.mAuthors.size(); index++) {
			Element authorELe = authorsEle.addElement("Author");
			authorELe.addAttribute("name", this.mAuthors.get(index).Name);
			authorELe.addAttribute("account", this.mAuthors.get(index).Account);
			
			Element institutionEle = authorELe.addElement("Institution");
			institutionEle.addAttribute("name", this.mAuthors.get(index).Institution.Name);
			institutionEle.addAttribute("country", this.mAuthors.get(index).Institution.City);
			institutionEle.addAttribute("city", this.mAuthors.get(index).Institution.City);
			institutionEle.addAttribute("address", this.mAuthors.get(index).Institution.Address);
			
			Element contactsEle = authorELe.addElement("Contacts");
			for (int iContacts = 0; iContacts < this.mAuthors.get(index).Contacts.size(); iContacts++) {
				Element contactEle = contactsEle.addElement("Add");
				contactEle.addAttribute("type", LocalizationHelper.ContactType2String(this.mAuthors.get(index).Contacts.get(iContacts).Type));
				contactEle.addAttribute("value", this.mAuthors.get(index).Contacts.get(iContacts).Value);
			}
		}
		
		for (int index = 0; index < this.mBuilders.size(); index++) {
			Element authorELe = buildersEle.addElement("Builder");
			authorELe.addAttribute("name", this.mBuilders.get(index).Name);
			authorELe.addAttribute("account", this.mBuilders.get(index).Account);
			
			Element institutionEle = authorELe.addElement("Institution");
			institutionEle.addAttribute("name", this.mBuilders.get(index).Institution.Name);
			institutionEle.addAttribute("country", this.mBuilders.get(index).Institution.City);
			institutionEle.addAttribute("city", this.mBuilders.get(index).Institution.City);
			institutionEle.addAttribute("address", this.mBuilders.get(index).Institution.Address);
			
			Element contactsEle = authorELe.addElement("Contacts");
			for (int iContacts = 0; iContacts < this.mBuilders.get(index).Contacts.size(); iContacts++) {
				Element contactEle = contactsEle.addElement("Add");
				contactEle.addAttribute("type", LocalizationHelper.ContactType2String(this.mBuilders.get(index).Contacts.get(iContacts).Type));
				contactEle.addAttribute("value", this.mBuilders.get(index).Contacts.get(iContacts).Value);
			}
		}
		
		for (int index = 0; index < this.mWrappers.size(); index++) {
			Element authorELe = wrappersEle.addElement("Wrapper");
			authorELe.addAttribute("name", this.mWrappers.get(index).Name);
			authorELe.addAttribute("account", this.mWrappers.get(index).Account);
			
			Element institutionEle = authorELe.addElement("Institution");
			institutionEle.addAttribute("name", this.mWrappers.get(index).Institution.Name);
			institutionEle.addAttribute("country", this.mWrappers.get(index).Institution.City);
			institutionEle.addAttribute("city", this.mWrappers.get(index).Institution.City);
			institutionEle.addAttribute("address", this.mWrappers.get(index).Institution.Address);
			
			Element contactsEle = authorELe.addElement("Contacts");
			for (int iContacts = 0; iContacts < this.mWrappers.get(index).Contacts.size(); iContacts++) {
				Element contactEle = contactsEle.addElement("Add");
				contactEle.addAttribute("type", LocalizationHelper.ContactType2String(this.mWrappers.get(index).Contacts.get(iContacts).Type));
				contactEle.addAttribute("value", this.mWrappers.get(index).Contacts.get(iContacts).Value);
			}
		}
		
		return true;
	}

	public int getLocalAttributeCount() {
		return mLocalAttributeList.size();
	}

	public LocalAttribute getLocalAttribute(int idx) {
		if (idx < 0 || idx >= mLocalAttributeList.size())
			return null;
		LocalAttribute pLocalAttribute = mLocalAttributeList.get(idx);
		return pLocalAttribute;
	}

	public LocalAttribute getLocalAttribute(ELocalizationType pLocalType) {
		for (int i = 0; i < mLocalAttributeList.size(); i++) {
			if (mLocalAttributeList.get(i).localType == pLocalType) {
				LocalAttribute pLocalAttribute = mLocalAttributeList.get(i);
				return pLocalAttribute;
			}
		}
		return null;
	}

	public boolean addLocalAttributeInfo(LocalAttribute pLocalAttribute) {
		for (int i = 0; i < mLocalAttributeList.size(); i++) {
			if (mLocalAttributeList.get(i).localType == pLocalAttribute.localType) {
				return false;
			}
		}
		mLocalAttributeList.add(pLocalAttribute);
		return true;
	}

	public boolean removeLocalAttribute(int idx) {
		if (idx < 0 || idx >= mLocalAttributeList.size())
			return false;
		mLocalAttributeList.remove(idx);
		return true;
	}

	public boolean removeLocalAttribute(LocalAttribute pLocalAttribute) {
		if (mLocalAttributeList.contains(pLocalAttribute)) {
			mLocalAttributeList.remove(pLocalAttribute);
			return true;
		}
		return false;
	}

	public boolean updateLocalAttribute(int idx, LocalAttribute pLocalAttribute) {
		if (idx < 0 || idx >= mLocalAttributeList.size())
			return false;
		mLocalAttributeList.remove(idx);
		mLocalAttributeList.add(idx, pLocalAttribute);
		return true;
	}

	public boolean updateLocalAttribute(ELocalizationType pLocalType,
			LocalAttribute pLocalAttribute) {
		for (int i = 0; i < mLocalAttributeList.size(); i++) {
			if (mLocalAttributeList.get(i).localType == pLocalType) {
				mLocalAttributeList.remove(i);
				mLocalAttributeList.add(i, pLocalAttribute);
				return true;
			}
		}
		return false;
	}

	// ////////////////////////////////////////////////////////////////////////
	public int getCategoryCount() {
		return mModelCategoryList.size();
	}

	public ModelCategory getCategory(int idx) {
		if (idx < 0 || idx >= mModelCategoryList.size())
			return null;
		ModelCategory pModelCategory = mModelCategoryList.get(idx);
		return pModelCategory;
	}

	public boolean addCategoryInfo(ModelCategory pCategoryInfo) {
		for (int i = 0; i < mModelCategoryList.size(); i++) {
			ModelCategory it = mModelCategoryList.get(i);
			if (it.principle.equals(pCategoryInfo.principle)
					&& it.path.equals(pCategoryInfo.path)) {
				return false;
			}
		}
		mModelCategoryList.add(pCategoryInfo);
		return true;
	}

	public boolean removeCategory(int idx) {
		if (idx < 0 || idx >= mModelCategoryList.size())
			return false;
		mModelCategoryList.remove(idx);
		return true;
	}

	public boolean removeCategory(ModelCategory pCategoryInfo) {
		if (mModelCategoryList.contains(pCategoryInfo)) {
			mModelCategoryList.remove(pCategoryInfo);
			return true;
		}
		return false;
	}

	public boolean updateCategory(int idx, ModelCategory pCategoryInfo) {
		if (idx < 0 || idx >= mModelCategoryList.size())
			return false;
		mModelCategoryList.remove(idx);
		mModelCategoryList.add(idx, pCategoryInfo);
		return true;
	}

	public boolean compareOther(ModelAttribute pAttribute, CompareFlag compareFlag) {
		if (pAttribute.getCategoryCount() != mModelCategoryList.size()) {
			compareFlag.Obj = "Categories";
			compareFlag.Name = "CategoryCount";
			return false;
		}
		for (int i = 0; i < mModelCategoryList.size(); i++) {
			ModelCategory temp_cate1 = mModelCategoryList.get(i);
			ModelCategory temp_cate2 = pAttribute.getCategory(i);
			if (temp_cate1.compareOther(temp_cate2) == false) {
				compareFlag.Obj = "Category";
				compareFlag.Name = temp_cate1.principle + "<->" + temp_cate2.principle;
				return false;
			}
		}
		if (pAttribute.getLocalAttributeCount() != mLocalAttributeList.size()) {
			compareFlag.Obj = "LocalAttributes";
			compareFlag.Name = "LocalAttributeCount";
			return false;
		}
		for (int i = 0; i < mLocalAttributeList.size(); i++) {
			LocalAttribute temp_local1 = mLocalAttributeList.get(i);
			LocalAttribute temp_local2 =pAttribute.getLocalAttribute(i);
			if (temp_local1.compareOther(temp_local2) == false) {
				compareFlag.Obj = "Category";
				compareFlag.Name = temp_local1.localType + "<->" + temp_local2.localType;
				return false;
			}
		}
		return true;
	}
	
	//////////////////////////////////////////////
	
	public boolean addAuthor(ModelUser ma) {
		return this.mAuthors.add(ma);
	}
	
	public int getAuthorCount() {
		return this.mAuthors.size();
	}
	
	public ModelUser getAuthor(int index) {
		if (index > (this.mAuthors.size() - 1)) return null;
		return this.mAuthors.get(index);
	}
	
	public boolean removeAuthor(int index) {
		if (index > (this.mAuthors.size() - 1)) return false;
		this.mAuthors.remove(index);
		return true;
	}
	
	public boolean removeAuthor(ModelUser ma) {
		return this.mAuthors.remove(ma);
	}
	
	
	
	public boolean addBuilder(ModelUser ma) {
		return this.mBuilders.add(ma);
	}
	
	public int getBuilderCount() {
		return this.mBuilders.size();
	}
	
	public ModelUser getBuilder(int index) {
		if (index > (this.mBuilders.size() - 1)) return null;
		return this.mBuilders.get(index);
	}
	
	public boolean removeBuilder(int index) {
		if (index > (this.mBuilders.size() - 1)) return false;
		this.mBuilders.remove(index);
		return true;
	}
	
	public boolean removeBuilder(ModelUser ma) {
		return this.mBuilders.remove(ma);
	}

	
	
	public boolean addWrapper(ModelUser ma) {
		return this.mWrappers.add(ma);
	}
	
	public int getWrapperCount() {
		return this.mWrappers.size();
	}
	
	public ModelUser getWrapper(int index) {
		if (index > (this.mWrappers.size() - 1)) return null;
		return this.mWrappers.get(index);
	}
	
	public boolean removeWrapper(int index) {
		if (index > (this.mWrappers.size() - 1)) return false;
		this.mWrappers.remove(index);
		return true;
	}
	
	public boolean removeWrapper(ModelUser ma) {
		return this.mWrappers.remove(ma);
	}

	private ArrayList<LocalAttribute> mLocalAttributeList;
	private ArrayList<ModelCategory> mModelCategoryList;

	private ArrayList<ModelUser> mAuthors;
	private ArrayList<ModelUser> mBuilders;
	private ArrayList<ModelUser> mWrappers;
}
